#include <cassert>
#include <algorithm>
#include <string>
#include <boost/lexical_cast.hpp>
#include "shader_light_system.h"
#include "ltbasedefs.h"

#define MAX_SHADER_LIGHT_NUMBER 4
shader_light_system::shader_light_system() {
    //  for(int i = 0 ; i < MAX_SHADER_LIGHT_NUMBER ; i++) {
    //    m_lights.push_back(shader_light()) ;
    // }
    m_ambient[0] = 0.13f ;
    m_ambient[1] = 0.13f ;
    m_ambient[2] = 0.13f ;
    m_ambient[3] = 1.0f ;
}

void shader_light_system::set_info(float* address, const float* data, int num) {
    for(int i = 0 ; i < num ; ++i) {
        address[i] = data[i] ;
    }
}

struct caculate_near_lights {
    const LTVector& m_pos ;
    caculate_near_lights(const LTVector& pos) : m_pos(pos) {}

    bool operator()(const shader_light& lhs,
                    const shader_light& rhs)const  {
        LTVector lhs_pos(lhs.Position[0], lhs.Position[1], lhs.Position[2]) ;
        LTVector rhs_pos(rhs.Position[0], rhs.Position[1], rhs.Position[3]) ;
        return lhs_pos.DistSqr(m_pos) < rhs_pos.DistSqr(m_pos) ;
    }
} ;

void shader_light_system::range_light_by_distance(const LTVector& pos) {
    std::sort(m_lights.begin(),
              m_lights.end(),
              caculate_near_lights(pos)) ;
}


void shader_light_system::set_ambient(const float* ambient) {
    // use memcpy
    //FIXME
    set_info(m_ambient, ambient, 4) ;
}

void shader_light_system::set_light_position(int id, const float* position) {
    
    set_info(m_lights[id].Position, position, 4) ;
}

void shader_light_system::set_light_color(int id, const float* color) {
    
    set_info(m_lights[id].Color, color, 4) ;
}

void shader_light_system::set_light_constane_attenuation(int id, float ca) {
    
        m_lights[id].ConstanceAttenuation = ca ;
}

void shader_light_system::set_light_linear_attenuation(int id, float cl) {
    
        m_lights[id].LinearAttenuation = cl ;
}

void shader_light_system::set_light_quadratic_attenuation(int id, float cq) {
    
        m_lights[id].QuadraticAttenuation = cq ;
}

void shader_light_system::use_lights(LTEffectShader* pEffect, float factor, const float* pp, float radius,
    int max_lights) {
//    m_lights[1].Color[2] = 1.0f ;
    //m_lights[0].Color[1] = 1.0f ;
    //m_lights[0].Color[0] = 1.0f ;
    //m_lights[0].Color[2] = 1.0f ;
    //m_lights[0].Position[0] = -128.0f ;
    //m_lights[2].Position[2] = 768.0f ;
    //m_lights[0].Position[1] = 576.0f ;
    pEffect->SetFloatArray("g_light_ambient", m_ambient, 4) ;
    pEffect->SetFloat("g_light_factor", factor) ;
    pEffect->SetFloat("g_darker_radius", radius) ;
    float ppp[3] ;
    ppp[0] = pp[0] ;
    ppp[1] = pp[1] ;
    ppp[2] = pp[2] ;
    pEffect->SetFloatArray("g_darker_position", ppp,3) ;
    max_lights = max_lights > m_lights.size() ? m_lights.size() : max_lights ;
    for(int i = 0 ; i < max_lights ; ++i) {
        std::string ivalue = boost::lexical_cast<std::string>(i);
        std::string g_light_b("g_light[") ;
        std::string g_light_position("].position") ;
        std::string g_light_color("].color") ;
        std::string g_light_constant("].constantAttenuation") ;
        pEffect->SetFloatArray
            ((g_light_b + ivalue + g_light_position).c_str(), m_lights[i].Position, 4) ;
        pEffect->SetFloatArray
            ((g_light_b + ivalue + g_light_color).c_str(), m_lights[i].Color, 4) ;
        pEffect->SetFloat((g_light_b+ivalue+g_light_constant).c_str(),
                          m_lights[i].ConstanceAttenuation) ;
        std::string g_light_linear("].linearAttenuation") ;
        pEffect->SetFloat((g_light_b + ivalue + g_light_linear).c_str(),
                          m_lights[i].LinearAttenuation) ;
        std::string g_light_quad("].quadraticAttenuation") ;
        pEffect->SetFloat((g_light_b + ivalue + g_light_quad).c_str(),
                          m_lights[i].QuadraticAttenuation) ;
    }
}
